'''
项目介绍:商城类智能助手
商城Agent是一个基于大模型的智能助手,旨在为用户提供关于商品信息的智能查询和服务。该项目结合了自然语言处理与数据库查询技术,使得用户可以通过自然语言与系统交互,获取商品库存、规格等信息。
本项目采用Python语言编写,利用了SQLite作为后端数据库来存储商品信息,并通过一个基于Qwen3-4b模型的智能代理来处理用户的查询请求。系统设计考虑了在消费级硬件上的运行效率。

项目功能：
1. 智能对话：基于大模型实现自然语言的智能对话。
2. 数据库连接：能够连接到数据库，并根据商品数据回答用户关于商品库存和规格的问题。
3. 工具调用：能够调用外部工具，如数据库查询、网页搜索等。
4. 对话历史打印：输入“打印历史对话”可以查看之前的对话记录。
5. 自主退出：输入“退出”即可结束当前对话。
6. 支持多轮对话：具有短时记忆能力，支持连续多轮的对话交互。

本代码需要调用函数Connect_Sql.py中的函数query_by_product_name
Code by Zyy

2025.10.1更新
完善了agent调用工具的历史对话回传
By Zyy


2025.10.1 晚20:16更新
对工具调用进行封装

2025.10.4 下午15:55更新
优化了工具并行调用的逻辑
By Zyy

2025.10.4 下午16:05更新
对用户异常输入进行处理
By Zyy

2025.10.4 晚19:45更新
添加了商品促销信息查询功能，优化了并行工具调用的逻辑
By Zyy
'''

from openai import OpenAI
import json 
import Connect_Sql
import read_store_promtions
# 创建OpenAI对象
client = OpenAI(
    base_url='http://localhost:11434/v1',
    api_key='zyy'
)
print('欢迎来到UpDownSeek商城')
# 创建消息列表
messages = [
  {'role':'system','content':'你是UpDownSeek商城助手，致力于为客户提供有用的信息和帮助。用中文回答客户问题。'},
]
# 定义查询函数调用的JSON Schema
product_Json_Schema = {
            'name':'query_by_product_name', #函数名称
            'description':'查询数据库来检索匹配包含指定产品名称的产品列表。此功能可用于帮助客户按名称查找产品，当用户询问某类产品还有吗，你们这边都有什么xx产品等，可以使用这个功能来查询是否有该产品', #函数描述
            'parameters':{ #函数参数
                'type':'object', #参数类型
                'properties':{ #参数名称
                    'product_name':{ #query_by_product_name函数的参数名称
                        'type':'string', #参数类型
                        'description':'你要要搜索的产品名称。' #参数描述
                    }
                },
                'required':['product_name'] #如果调用该函数的话，必须要上传该参数
            }
  }
promotions_Json_Schema = {
            'name':'read_store_promotions', #函数名称
            'description':'查询商品名称来匹配包含指定产品名称的产品优惠政策。此功能可用于帮助客户按名称搜索商品优惠政策，当用户询问某类产品有促销政策吗，你们这边都某商品优惠活动等，可以使用这个功能来查询该产品是否有优惠活动', #函数描述
            'parameters':{ #函数参数
                'type':'object', #参数类型
                'properties':{ #参数名称
                    'product_name':{ #query_by_product_name函数的参数名称
                        'type':'string', #参数类型
                        'description':'你要要搜索的产品名称。' #参数描述
                    }
                },
                'required':['product_name'] #如果调用该函数的话，必须要上传该参数
            }
  }
# 创建工具列表
tools = [{
  'type':'function',
  'function':product_Json_Schema
},{
  'type':'function',
  'function':promotions_Json_Schema
}
]
while True:
  # 获取用户输入
  print('_'*50)
  prompt = input('用户输入：')
  # 打印历史对话
  if prompt.lower() in ['打印历史对话']:
    print(messages)
    continue
  # 如果输入退出，则退出对话
  if prompt.lower() in ['退出','bye']:
    print('感谢您的支持，再见！')
    break
  if not prompt.strip():
      print('输入不能为空，请重新输入')
      continue
  # 如果输入其他内容，则进行对话
  else:
      messages.append({'role':'user','content':prompt})
      response = client.chat.completions.create(
        model='qwen3:4b',
        messages=messages,
        tools=tools,
        parallel_tool_calls=True, # 是否并行调用工具
        temperature=0.1, #降低温度值，获得更稳定的输出
        )
      # 判断是否调用了工具
      if response.choices[0].message.tool_calls:  
          #print('模型决定调用工具')
          #回传对话
          messages.append(response.choices[0].message)
          # print('对话回传成功：',response.choices[0].message)
          #语法糖封装
          #print('共有以下tool_calls：',response.choices[0].message.tool_calls)
          tool_calls = response.choices[0].message.tool_calls
          for tool_call in tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)
            available_functions ={'query_by_product_name':Connect_Sql.query_by_product_name,'read_store_promotions':read_store_promtions.read_store_promotions}
            function_to_call = available_functions[function_name]
            function_response = function_to_call(**function_args)
            if function_name == 'query_by_product_name': 
              product_content = '' # 用于存储格式化后的商品信息
              
              for i in function_response:
                
                product_content += f'商品编号：{i[0]}商品名：{i[1]}, 描述：{i[2]}, 规格：{i[3]}, 用途：{i[4]}, 品牌：{i[5]}, 价格：{i[6]}元, 库存：{i[7]}/end'
              messages.append(
                  {'role':'tool','name':function_name,'tool_call_id':tool_call.id,'content':str(product_content)}
              )
            elif function_name == 'read_store_promotions':
              # print(f'函数名称：{function_name}\n参数：{function_args}\n结果：{function_response}')
              messages.append(
                  {'role':'tool','name':function_name,'tool_call_id':tool_call.id,'content':str(function_response)}
              )
          #print('工具调用结果回传成功')
          # print('-'*50)
          # print('历史：',messages)
        #再次生成回复
          response = client.chat.completions.create(
        model='qwen3:4b',
        messages=messages,
        )
    #无论是否调用工具，都要输出回复，并且添加到消息列表中   
      print('助手：',response.choices[0].message.content)
      # print(response.choices[0].message)
      messages.append({'role':'assistant','content':response.choices[0].message.content})

    
    
      
